package com.bianmaba.activiti.service.authorization.role;

import com.bianmaba.spring.web.service.BaseService;
import com.bianmaba.activiti.beans.entity.authorization.Role;
import com.bianmaba.activiti.beans.entity.authorization.User;
import com.bianmaba.activiti.repository.authorization.role.RoleRepository;
import com.bianmaba.spring.security.util.SecurityUtils;
import org.activiti.engine.IdentityService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by cwx183898 on 2017/12/14.
 */
@Service
public class RoleService extends BaseService<Role, String> implements IRoleService {
    private static final Logger LOG = LoggerFactory.getLogger(RoleService.class);
    @Autowired
    private RoleRepository repository;
    @Autowired
    private IdentityService identityService;


    @Override
    public RoleRepository getRepository() {
        return repository;
    }

    @Override
    public Role save(Role entity) {
        String username = SecurityUtils.getCurrentUsername();
        if (entity.getCreator() == null) {
            entity.setCreator(username);
        }

        List<User> oldUsers = null;
        if (!StringUtils.isEmpty(entity.getId())) {
            oldUsers = super.findOne(entity.getId()).getUsers();
        }
        Role role = super.save(entity);
        addActivitiGroupAndUsers(role, oldUsers);
        return role;
    }

    @Override
    public String delete(String id) {
        this.delete(Arrays.asList(new String[]{id}));
        return id;
    }

    @Override
    public List<String> delete(String[] ids) {
        return this.delete(Arrays.asList(ids));
    }

    @Override
    public List<String> delete(List<String> ids) {
        List<Role> roles = findAllById(ids.toArray(new String[ids.size()]));
        if (!roles.isEmpty()) {
            delete(roles.toArray(new Role[roles.size()]));
            String[] names = new String[roles.size()];
            for (int i = 0; i < roles.size(); i++) {
                names[i] = roles.get(i).getName();
            }
            deleteActivitiGroups(names);
            return ids;
        } else {
            return Collections.emptyList();
        }
    }


    private void deleteActivitiGroups(String[] names) {
        for (String name : names) {
            identityService.deleteGroup(name);
        }
    }

    private void addActivitiGroupAndUsers(Role entity, List<User> oldUsers) {
        org.activiti.engine.identity.Group ag = identityService.createGroupQuery().groupId(entity.getName()).singleResult();

        //activiti中不存在指定的角色时添加
        if (ag == null) {
            ag = identityService.newGroup(entity.getName());
            ag.setName(entity.getName());
        } else {
            //防止角色名称修改，这里同步一次
            ag.setName(entity.getName());

            //将所有关联用户删除，后边重新关联
            if (oldUsers != null) {
                for (User user : oldUsers) {
                    identityService.deleteMembership(user.getUsername(), ag.getName());
                }
            }
        }
        identityService.saveGroup(ag);

        //关联用户与角色
        List<User> users = new ArrayList<>(entity.getUsers());
        if (!users.isEmpty()) {
            for (User user : users) {
                org.activiti.engine.identity.User au = identityService.createUserQuery().userId(user.getUsername()).singleResult();
                if (au == null) {
                    au = identityService.newUser(user.getUsername());
                    au.setFirstName(user.getName());
                    identityService.saveUser(au);
                }
                identityService.createMembership(user.getUsername(), entity.getName());
            }
        }
    }

    @Override
    public List<Role> findAllByUserId(String userId) {
        Map params = new HashMap() {{
            put("users.id", userId);
        }};
        List<Role> roles = repository.queryToList(params);
        return roles;
    }
}
